{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "9a5fab2e-75e4-45f0-a158-6c0484664513",
   "metadata": {},
   "outputs": [],
   "source": [
    "# pytorch\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "# Mobile Net\n",
    "# from MobileNetV2 import mobilenet_v2\n",
    "from MobileNetV3 import mobilenetv3_large, mobilenetv3_small\n",
    "# dataset\n",
    "from torchvision import datasets\n",
    "from torchvision import transforms\n",
    "# dataloader\n",
    "from torch.utils.data import DataLoader\n",
    "# Util\n",
    "import time\n",
    "import datetime\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import copy\n",
    "# tensorboard\n",
    "from torch.utils.tensorboard import SummaryWriter\n",
    "# plt\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "plt.rcParams['font.family'] = 'Noto Sans CJK JP'\n",
    "matplotlib.rcParams.update({'font.size': 13})\n",
    "import scipy.io as scio\n",
    "from scipy.io import loadmat\n",
    "from sklearn.model_selection import KFold"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "136ba4e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# loss下降曲线vec\n",
    "vec1 = [] #0.01\n",
    "vec2 = [] #0.005\n",
    "vec3 = [] #0.001\n",
    "vec4 = [] #0.0005"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "61e43e83",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 超参数\n",
    "input_size = 224\n",
    "batch_size = 32\n",
    "n_worker = 8\n",
    "lr = 0.001\n",
    "epochs = 80"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "916c1c6f-6228-4d64-928d-68c045094bd4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成训练数据集\n",
    "train_path = \"image/train_image\"\n",
    "test_path = \"image/train_image\"\n",
    "val_path = \"image/val_image\"\n",
    "data_transform = transforms.Compose([\n",
    "        transforms.Resize([input_size, input_size]),\n",
    "        transforms.ToTensor(),\n",
    "])\n",
    "train_dataset = datasets.ImageFolder(train_path, transform=data_transform)\n",
    "test_dataset = datasets.ImageFolder(test_path, transform=data_transform)\n",
    "val_dataset = datasets.ImageFolder(val_path, transform=data_transform)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "63a6157c-189f-46fc-9698-f8b99af5efe6",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_loader = DataLoader(\n",
    "    train_dataset, batch_size=batch_size, shuffle=True,\n",
    "    num_workers=n_worker, pin_memory=True)\n",
    "test_loader = DataLoader(\n",
    "    test_dataset, batch_size=20, shuffle=False, \n",
    "    num_workers=n_worker)\n",
    "val_loader = DataLoader(\n",
    "    val_dataset, batch_size=5, shuffle=False, \n",
    "    num_workers=n_worker)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "4c7b0afc",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = mobilenetv3_large()\n",
    "# model = mobilenet_v2()\n",
    "model.classifier[3] = nn.Linear(1280, 90)\n",
    "model = model.cuda(3)\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=lr)\n",
    "# scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.97)\n",
    "best_model_wts = copy.deepcopy(model.state_dict())\n",
    "# writer = SummaryWriter()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "75e7a13a-3f06-4de6-9e6a-cea34fa8c28f",
   "metadata": {},
   "outputs": [],
   "source": [
    "def train(epoch, model):\n",
    "    model.train()\n",
    "    train_loss = 0\n",
    "    for data, label in train_loader:\n",
    "        data, label = data.cuda(3), label.cuda(3)\n",
    "        # clear the grad\n",
    "        optimizer.zero_grad()\n",
    "        output = model(data)\n",
    "        # loss function\n",
    "        loss = criterion(output, label)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        # scheduler.step()\n",
    "        train_loss += loss.item() * data.size(0)\n",
    "    train_loss = train_loss / len(train_loader.dataset)\n",
    "    # writer.add_scalar(\"Loss/train\", train_loss, epoch)\n",
    "    print('Epoch: {} \\tTraining Loss: {:.6f}'.format(epoch, train_loss))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "7af63268-0bcc-4404-a89d-4c17d6f1b0ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "def val(epoch, model):       \n",
    "    model.eval()\n",
    "    idx = 0\n",
    "    ans = 0.0\n",
    "    best_acc = 0.0\n",
    "    ri_ct = 0.0\n",
    "    with torch.no_grad():\n",
    "        for data, label in val_loader:\n",
    "            data, label = data.cuda(3), label.cuda(3)\n",
    "            output = model(data)\n",
    "            preds = torch.argmax(output, 1)\n",
    "            ri_ct += (preds == idx).sum().item()\n",
    "            unique_values, counts = torch.unique(preds, return_counts=True)\n",
    "            pres = unique_values[counts.argmax()]\n",
    "            if pres.item() == idx:\n",
    "                ans += 1\n",
    "            idx += 1\n",
    "    acc = ans / 90\n",
    "    r = ri_ct / 540\n",
    "    print('Epoch: {} Val Accuracy: {:6f}'.format(epoch, acc))\n",
    "    print('Epoch: {} Val Recall: {:6f}'.format(epoch, r))\n",
    "    return acc, r"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "24a8cfb1-cfaa-42ac-9fdd-fd1d708ac2d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "def test(epoch, model):\n",
    "    model.eval()\n",
    "    idx = 0\n",
    "    ans = 0.0\n",
    "    best_acc = 0.0\n",
    "    ri_ct = 0.0\n",
    "    with torch.no_grad():\n",
    "        for data, label in test_loader:\n",
    "            data, label = data.cuda(3), label.cuda(3)\n",
    "            output = model(data)\n",
    "            preds = torch.argmax(output, 1)\n",
    "            ri_ct += (preds == idx).sum().item()\n",
    "            unique_values, counts = torch.unique(preds, return_counts=True)\n",
    "            pres = unique_values[counts.argmax()]\n",
    "            if pres.item() == idx:\n",
    "                ans += 1\n",
    "            idx += 1\n",
    "    acc = ans / 90\n",
    "    r = ri_ct / 1800\n",
    "    if acc > best_acc:\n",
    "        best_model_wts = copy.deepcopy(model.state_dict())\n",
    "    print('Epoch: {} Test Accuracy: {:6f}'.format(epoch, acc))\n",
    "    print('Epoch: {} Test Recall: {:6f}'.format(epoch, r))\n",
    "    return acc, r"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0098d60d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 1 \tTraining Loss: 4.202651\n",
      "Epoch: 1 Val Accuracy: 0.022222\n",
      "Epoch: 1 Val Recall: 0.016667\n",
      "Epoch: 1 Test Accuracy: 0.011111\n",
      "Epoch: 1 Test Recall: 0.013889\n",
      "Epoch: 2 \tTraining Loss: 3.465046\n",
      "Epoch: 2 Val Accuracy: 0.088889\n",
      "Epoch: 2 Val Recall: 0.077778\n",
      "Epoch: 2 Test Accuracy: 0.111111\n",
      "Epoch: 2 Test Recall: 0.094444\n",
      "Epoch: 3 \tTraining Loss: 2.991243\n",
      "Epoch: 3 Val Accuracy: 0.133333\n",
      "Epoch: 3 Val Recall: 0.118519\n",
      "Epoch: 3 Test Accuracy: 0.211111\n",
      "Epoch: 3 Test Recall: 0.172222\n",
      "Epoch: 4 \tTraining Loss: 2.590376\n",
      "Epoch: 4 Val Accuracy: 0.122222\n",
      "Epoch: 4 Val Recall: 0.105556\n",
      "Epoch: 4 Test Accuracy: 0.233333\n",
      "Epoch: 4 Test Recall: 0.176111\n",
      "Epoch: 5 \tTraining Loss: 2.329601\n",
      "Epoch: 5 Val Accuracy: 0.266667\n",
      "Epoch: 5 Val Recall: 0.209259\n",
      "Epoch: 5 Test Accuracy: 0.400000\n",
      "Epoch: 5 Test Recall: 0.312222\n",
      "Epoch: 6 \tTraining Loss: 1.983463\n",
      "Epoch: 6 Val Accuracy: 0.477778\n",
      "Epoch: 6 Val Recall: 0.307407\n",
      "Epoch: 6 Test Accuracy: 0.611111\n",
      "Epoch: 6 Test Recall: 0.506667\n",
      "Epoch: 7 \tTraining Loss: 1.836859\n",
      "Epoch: 7 Val Accuracy: 0.433333\n",
      "Epoch: 7 Val Recall: 0.296296\n",
      "Epoch: 7 Test Accuracy: 0.611111\n",
      "Epoch: 7 Test Recall: 0.485556\n",
      "Epoch: 8 \tTraining Loss: 1.616829\n",
      "Epoch: 8 Val Accuracy: 0.477778\n",
      "Epoch: 8 Val Recall: 0.338889\n",
      "Epoch: 8 Test Accuracy: 0.744444\n",
      "Epoch: 8 Test Recall: 0.586667\n",
      "Epoch: 9 \tTraining Loss: 1.346821\n",
      "Epoch: 9 Val Accuracy: 0.233333\n",
      "Epoch: 9 Val Recall: 0.187037\n",
      "Epoch: 9 Test Accuracy: 0.433333\n",
      "Epoch: 9 Test Recall: 0.328333\n",
      "Epoch: 10 \tTraining Loss: 1.210202\n",
      "Epoch: 10 Val Accuracy: 0.455556\n",
      "Epoch: 10 Val Recall: 0.331481\n",
      "Epoch: 10 Test Accuracy: 0.766667\n",
      "Epoch: 10 Test Recall: 0.612222\n",
      "Epoch: 11 \tTraining Loss: 1.260990\n",
      "Epoch: 11 Val Accuracy: 0.366667\n",
      "Epoch: 11 Val Recall: 0.262963\n",
      "Epoch: 11 Test Accuracy: 0.566667\n",
      "Epoch: 11 Test Recall: 0.468333\n",
      "Epoch: 12 \tTraining Loss: 1.050259\n",
      "Epoch: 12 Val Accuracy: 0.477778\n",
      "Epoch: 12 Val Recall: 0.337037\n",
      "Epoch: 12 Test Accuracy: 0.900000\n",
      "Epoch: 12 Test Recall: 0.735556\n",
      "Epoch: 13 \tTraining Loss: 0.958025\n",
      "Epoch: 13 Val Accuracy: 0.555556\n",
      "Epoch: 13 Val Recall: 0.370370\n",
      "Epoch: 13 Test Accuracy: 0.933333\n",
      "Epoch: 13 Test Recall: 0.747778\n",
      "Epoch: 14 \tTraining Loss: 0.871856\n",
      "Epoch: 14 Val Accuracy: 0.633333\n",
      "Epoch: 14 Val Recall: 0.405556\n",
      "Epoch: 14 Test Accuracy: 0.888889\n",
      "Epoch: 14 Test Recall: 0.767778\n",
      "Epoch: 15 \tTraining Loss: 0.798582\n",
      "Epoch: 15 Val Accuracy: 0.511111\n",
      "Epoch: 15 Val Recall: 0.342593\n",
      "Epoch: 15 Test Accuracy: 0.788889\n",
      "Epoch: 15 Test Recall: 0.667222\n",
      "Epoch: 16 \tTraining Loss: 0.616244\n",
      "Epoch: 16 Val Accuracy: 0.611111\n",
      "Epoch: 16 Val Recall: 0.438889\n",
      "Epoch: 16 Test Accuracy: 0.966667\n",
      "Epoch: 16 Test Recall: 0.875556\n",
      "Epoch: 17 \tTraining Loss: 0.516857\n",
      "Epoch: 17 Val Accuracy: 0.733333\n",
      "Epoch: 17 Val Recall: 0.485185\n",
      "Epoch: 17 Test Accuracy: 0.977778\n",
      "Epoch: 17 Test Recall: 0.862778\n",
      "Epoch: 18 \tTraining Loss: 0.474587\n",
      "Epoch: 18 Val Accuracy: 0.577778\n",
      "Epoch: 18 Val Recall: 0.377778\n",
      "Epoch: 18 Test Accuracy: 0.822222\n",
      "Epoch: 18 Test Recall: 0.673889\n",
      "Epoch: 19 \tTraining Loss: 0.635099\n",
      "Epoch: 19 Val Accuracy: 0.722222\n",
      "Epoch: 19 Val Recall: 0.490741\n",
      "Epoch: 19 Test Accuracy: 0.988889\n",
      "Epoch: 19 Test Recall: 0.916111\n",
      "Epoch: 20 \tTraining Loss: 0.370326\n",
      "Epoch: 20 Val Accuracy: 0.755556\n",
      "Epoch: 20 Val Recall: 0.457407\n",
      "Epoch: 20 Test Accuracy: 1.000000\n",
      "Epoch: 20 Test Recall: 0.851111\n",
      "Epoch: 21 \tTraining Loss: 0.454584\n",
      "Epoch: 21 Val Accuracy: 0.744444\n",
      "Epoch: 21 Val Recall: 0.464815\n",
      "Epoch: 21 Test Accuracy: 0.977778\n",
      "Epoch: 21 Test Recall: 0.928333\n",
      "Epoch: 22 \tTraining Loss: 0.478713\n",
      "Epoch: 22 Val Accuracy: 0.744444\n",
      "Epoch: 22 Val Recall: 0.479630\n",
      "Epoch: 22 Test Accuracy: 1.000000\n",
      "Epoch: 22 Test Recall: 0.932222\n",
      "Epoch: 23 \tTraining Loss: 0.389862\n",
      "Epoch: 23 Val Accuracy: 0.722222\n",
      "Epoch: 23 Val Recall: 0.481481\n",
      "Epoch: 23 Test Accuracy: 1.000000\n",
      "Epoch: 23 Test Recall: 0.932222\n",
      "Epoch: 24 \tTraining Loss: 0.273684\n",
      "Epoch: 24 Val Accuracy: 0.777778\n",
      "Epoch: 24 Val Recall: 0.537037\n",
      "Epoch: 24 Test Accuracy: 1.000000\n",
      "Epoch: 24 Test Recall: 0.946111\n",
      "Epoch: 25 \tTraining Loss: 0.226057\n",
      "Epoch: 25 Val Accuracy: 0.822222\n",
      "Epoch: 25 Val Recall: 0.540741\n",
      "Epoch: 25 Test Accuracy: 1.000000\n",
      "Epoch: 25 Test Recall: 0.982778\n",
      "Epoch: 26 \tTraining Loss: 0.309888\n",
      "Epoch: 26 Val Accuracy: 0.733333\n",
      "Epoch: 26 Val Recall: 0.487037\n",
      "Epoch: 26 Test Accuracy: 1.000000\n",
      "Epoch: 26 Test Recall: 0.959444\n",
      "Epoch: 27 \tTraining Loss: 0.242747\n",
      "Epoch: 27 Val Accuracy: 0.800000\n",
      "Epoch: 27 Val Recall: 0.550000\n",
      "Epoch: 27 Test Accuracy: 1.000000\n",
      "Epoch: 27 Test Recall: 0.968889\n",
      "Epoch: 28 \tTraining Loss: 0.316047\n",
      "Epoch: 28 Val Accuracy: 0.766667\n",
      "Epoch: 28 Val Recall: 0.509259\n",
      "Epoch: 28 Test Accuracy: 1.000000\n",
      "Epoch: 28 Test Recall: 0.948333\n",
      "Epoch: 29 \tTraining Loss: 0.368554\n",
      "Epoch: 29 Val Accuracy: 0.733333\n",
      "Epoch: 29 Val Recall: 0.503704\n",
      "Epoch: 29 Test Accuracy: 0.977778\n",
      "Epoch: 29 Test Recall: 0.918333\n",
      "Epoch: 30 \tTraining Loss: 0.179521\n",
      "Epoch: 30 Val Accuracy: 0.777778\n",
      "Epoch: 30 Val Recall: 0.529630\n",
      "Epoch: 30 Test Accuracy: 1.000000\n",
      "Epoch: 30 Test Recall: 0.976111\n",
      "Epoch: 31 \tTraining Loss: 0.154010\n",
      "Epoch: 31 Val Accuracy: 0.744444\n",
      "Epoch: 31 Val Recall: 0.494444\n",
      "Epoch: 31 Test Accuracy: 1.000000\n",
      "Epoch: 31 Test Recall: 0.957778\n",
      "Epoch: 32 \tTraining Loss: 0.215263\n",
      "Epoch: 32 Val Accuracy: 0.833333\n",
      "Epoch: 32 Val Recall: 0.557407\n",
      "Epoch: 32 Test Accuracy: 1.000000\n",
      "Epoch: 32 Test Recall: 0.971667\n",
      "Epoch: 33 \tTraining Loss: 0.311681\n",
      "Epoch: 33 Val Accuracy: 0.733333\n",
      "Epoch: 33 Val Recall: 0.498148\n",
      "Epoch: 33 Test Accuracy: 1.000000\n",
      "Epoch: 33 Test Recall: 0.944444\n",
      "Epoch: 34 \tTraining Loss: 0.178035\n",
      "Epoch: 34 Val Accuracy: 0.833333\n",
      "Epoch: 34 Val Recall: 0.581481\n",
      "Epoch: 34 Test Accuracy: 1.000000\n",
      "Epoch: 34 Test Recall: 0.987222\n",
      "Epoch: 35 \tTraining Loss: 0.183871\n",
      "Epoch: 35 Val Accuracy: 0.800000\n",
      "Epoch: 35 Val Recall: 0.572222\n",
      "Epoch: 35 Test Accuracy: 1.000000\n",
      "Epoch: 35 Test Recall: 0.974444\n",
      "Epoch: 36 \tTraining Loss: 0.289233\n",
      "Epoch: 36 Val Accuracy: 0.822222\n",
      "Epoch: 36 Val Recall: 0.575926\n",
      "Epoch: 36 Test Accuracy: 0.988889\n",
      "Epoch: 36 Test Recall: 0.956111\n",
      "Epoch: 37 \tTraining Loss: 0.229015\n",
      "Epoch: 37 Val Accuracy: 0.811111\n",
      "Epoch: 37 Val Recall: 0.557407\n",
      "Epoch: 37 Test Accuracy: 1.000000\n",
      "Epoch: 37 Test Recall: 0.972222\n",
      "Epoch: 38 \tTraining Loss: 0.188020\n",
      "Epoch: 38 Val Accuracy: 0.766667\n",
      "Epoch: 38 Val Recall: 0.553704\n",
      "Epoch: 38 Test Accuracy: 1.000000\n",
      "Epoch: 38 Test Recall: 0.975556\n",
      "Epoch: 39 \tTraining Loss: 0.187579\n",
      "Epoch: 39 Val Accuracy: 0.844444\n",
      "Epoch: 39 Val Recall: 0.561111\n",
      "Epoch: 39 Test Accuracy: 0.988889\n",
      "Epoch: 39 Test Recall: 0.973333\n",
      "Epoch: 40 \tTraining Loss: 0.134389\n",
      "Epoch: 40 Val Accuracy: 0.800000\n",
      "Epoch: 40 Val Recall: 0.533333\n",
      "Epoch: 40 Test Accuracy: 0.988889\n",
      "Epoch: 40 Test Recall: 0.968333\n",
      "Epoch: 41 \tTraining Loss: 0.168669\n",
      "Epoch: 41 Val Accuracy: 0.888889\n",
      "Epoch: 41 Val Recall: 0.601852\n",
      "Epoch: 41 Test Accuracy: 1.000000\n",
      "Epoch: 41 Test Recall: 0.989444\n",
      "Epoch: 42 \tTraining Loss: 0.094324\n",
      "Epoch: 42 Val Accuracy: 0.855556\n",
      "Epoch: 42 Val Recall: 0.603704\n",
      "Epoch: 42 Test Accuracy: 1.000000\n",
      "Epoch: 42 Test Recall: 0.989444\n",
      "Epoch: 43 \tTraining Loss: 0.064054\n",
      "Epoch: 43 Val Accuracy: 0.866667\n",
      "Epoch: 43 Val Recall: 0.616667\n",
      "Epoch: 43 Test Accuracy: 1.000000\n",
      "Epoch: 43 Test Recall: 0.995000\n",
      "Epoch: 44 \tTraining Loss: 0.089927\n",
      "Epoch: 44 Val Accuracy: 0.833333\n",
      "Epoch: 44 Val Recall: 0.566667\n",
      "Epoch: 44 Test Accuracy: 1.000000\n",
      "Epoch: 44 Test Recall: 0.971111\n",
      "Epoch: 45 \tTraining Loss: 0.133346\n",
      "Epoch: 45 Val Accuracy: 0.822222\n",
      "Epoch: 45 Val Recall: 0.559259\n",
      "Epoch: 45 Test Accuracy: 1.000000\n",
      "Epoch: 45 Test Recall: 0.971667\n",
      "Epoch: 46 \tTraining Loss: 0.175670\n",
      "Epoch: 46 Val Accuracy: 0.788889\n",
      "Epoch: 46 Val Recall: 0.548148\n",
      "Epoch: 46 Test Accuracy: 1.000000\n",
      "Epoch: 46 Test Recall: 0.945556\n",
      "Epoch: 47 \tTraining Loss: 0.174616\n",
      "Epoch: 47 Val Accuracy: 0.844444\n",
      "Epoch: 47 Val Recall: 0.572222\n",
      "Epoch: 47 Test Accuracy: 1.000000\n",
      "Epoch: 47 Test Recall: 0.976111\n",
      "Epoch: 48 \tTraining Loss: 0.273360\n",
      "Epoch: 48 Val Accuracy: 0.855556\n",
      "Epoch: 48 Val Recall: 0.561111\n",
      "Epoch: 48 Test Accuracy: 1.000000\n",
      "Epoch: 48 Test Recall: 0.948889\n",
      "Epoch: 49 \tTraining Loss: 0.192201\n",
      "Epoch: 49 Val Accuracy: 0.800000\n",
      "Epoch: 49 Val Recall: 0.538889\n",
      "Epoch: 49 Test Accuracy: 1.000000\n",
      "Epoch: 49 Test Recall: 0.974444\n",
      "Epoch: 50 \tTraining Loss: 0.264720\n",
      "Epoch: 50 Val Accuracy: 0.766667\n",
      "Epoch: 50 Val Recall: 0.524074\n",
      "Epoch: 50 Test Accuracy: 1.000000\n",
      "Epoch: 50 Test Recall: 0.976111\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 51 \tTraining Loss: 0.170132\n",
      "Epoch: 51 Val Accuracy: 0.722222\n",
      "Epoch: 51 Val Recall: 0.518519\n",
      "Epoch: 51 Test Accuracy: 1.000000\n",
      "Epoch: 51 Test Recall: 0.965556\n",
      "Epoch: 52 \tTraining Loss: 0.072549\n",
      "Epoch: 52 Val Accuracy: 0.777778\n",
      "Epoch: 52 Val Recall: 0.527778\n",
      "Epoch: 52 Test Accuracy: 1.000000\n",
      "Epoch: 52 Test Recall: 0.983333\n",
      "Epoch: 53 \tTraining Loss: 0.120120\n",
      "Epoch: 53 Val Accuracy: 0.888889\n",
      "Epoch: 53 Val Recall: 0.609259\n",
      "Epoch: 53 Test Accuracy: 1.000000\n",
      "Epoch: 53 Test Recall: 0.988333\n",
      "Epoch: 54 \tTraining Loss: 0.064833\n",
      "Epoch: 54 Val Accuracy: 0.877778\n",
      "Epoch: 54 Val Recall: 0.601852\n",
      "Epoch: 54 Test Accuracy: 1.000000\n",
      "Epoch: 54 Test Recall: 0.983333\n",
      "Epoch: 55 \tTraining Loss: 0.131218\n",
      "Epoch: 55 Val Accuracy: 0.811111\n",
      "Epoch: 55 Val Recall: 0.538889\n",
      "Epoch: 55 Test Accuracy: 0.988889\n",
      "Epoch: 55 Test Recall: 0.940556\n",
      "Epoch: 56 \tTraining Loss: 0.132681\n",
      "Epoch: 56 Val Accuracy: 0.833333\n",
      "Epoch: 56 Val Recall: 0.562963\n",
      "Epoch: 56 Test Accuracy: 1.000000\n",
      "Epoch: 56 Test Recall: 0.983889\n",
      "Epoch: 57 \tTraining Loss: 0.168389\n",
      "Epoch: 57 Val Accuracy: 0.822222\n",
      "Epoch: 57 Val Recall: 0.572222\n",
      "Epoch: 57 Test Accuracy: 1.000000\n",
      "Epoch: 57 Test Recall: 0.988889\n",
      "Epoch: 58 \tTraining Loss: 0.169523\n",
      "Epoch: 58 Val Accuracy: 0.788889\n",
      "Epoch: 58 Val Recall: 0.566667\n",
      "Epoch: 58 Test Accuracy: 1.000000\n",
      "Epoch: 58 Test Recall: 0.980000\n",
      "Epoch: 59 \tTraining Loss: 0.204996\n",
      "Epoch: 59 Val Accuracy: 0.833333\n",
      "Epoch: 59 Val Recall: 0.592593\n",
      "Epoch: 59 Test Accuracy: 1.000000\n",
      "Epoch: 59 Test Recall: 0.988333\n",
      "Epoch: 60 \tTraining Loss: 0.134643\n",
      "Epoch: 60 Val Accuracy: 0.833333\n",
      "Epoch: 60 Val Recall: 0.559259\n",
      "Epoch: 60 Test Accuracy: 1.000000\n",
      "Epoch: 60 Test Recall: 0.983333\n",
      "Epoch: 61 \tTraining Loss: 0.222349\n",
      "Epoch: 61 Val Accuracy: 0.766667\n",
      "Epoch: 61 Val Recall: 0.540741\n",
      "Epoch: 61 Test Accuracy: 1.000000\n",
      "Epoch: 61 Test Recall: 0.970556\n",
      "Epoch: 62 \tTraining Loss: 0.265832\n",
      "Epoch: 62 Val Accuracy: 0.777778\n",
      "Epoch: 62 Val Recall: 0.555556\n",
      "Epoch: 62 Test Accuracy: 1.000000\n",
      "Epoch: 62 Test Recall: 0.960556\n",
      "Epoch: 63 \tTraining Loss: 0.184824\n",
      "Epoch: 63 Val Accuracy: 0.800000\n",
      "Epoch: 63 Val Recall: 0.570370\n",
      "Epoch: 63 Test Accuracy: 1.000000\n",
      "Epoch: 63 Test Recall: 0.976667\n",
      "Epoch: 64 \tTraining Loss: 0.133570\n",
      "Epoch: 64 Val Accuracy: 0.822222\n",
      "Epoch: 64 Val Recall: 0.579630\n",
      "Epoch: 64 Test Accuracy: 1.000000\n",
      "Epoch: 64 Test Recall: 0.990556\n",
      "Epoch: 65 \tTraining Loss: 0.142358\n",
      "Epoch: 65 Val Accuracy: 0.844444\n",
      "Epoch: 65 Val Recall: 0.612963\n",
      "Epoch: 65 Test Accuracy: 1.000000\n",
      "Epoch: 65 Test Recall: 0.987778\n",
      "Epoch: 66 \tTraining Loss: 0.090257\n",
      "Epoch: 66 Val Accuracy: 0.888889\n",
      "Epoch: 66 Val Recall: 0.622222\n",
      "Epoch: 66 Test Accuracy: 1.000000\n",
      "Epoch: 66 Test Recall: 0.996111\n",
      "Epoch: 67 \tTraining Loss: 0.049219\n",
      "Epoch: 67 Val Accuracy: 0.855556\n",
      "Epoch: 67 Val Recall: 0.614815\n",
      "Epoch: 67 Test Accuracy: 1.000000\n",
      "Epoch: 67 Test Recall: 0.996111\n",
      "Epoch: 68 \tTraining Loss: 0.056524\n",
      "Epoch: 68 Val Accuracy: 0.911111\n",
      "Epoch: 68 Val Recall: 0.633333\n",
      "Epoch: 68 Test Accuracy: 1.000000\n",
      "Epoch: 68 Test Recall: 0.995556\n",
      "Epoch: 69 \tTraining Loss: 0.068017\n",
      "Epoch: 69 Val Accuracy: 0.877778\n",
      "Epoch: 69 Val Recall: 0.596296\n",
      "Epoch: 69 Test Accuracy: 1.000000\n",
      "Epoch: 69 Test Recall: 0.993333\n",
      "Epoch: 70 \tTraining Loss: 0.138008\n",
      "Epoch: 70 Val Accuracy: 0.833333\n",
      "Epoch: 70 Val Recall: 0.598148\n",
      "Epoch: 70 Test Accuracy: 1.000000\n",
      "Epoch: 70 Test Recall: 0.990556\n",
      "Epoch: 71 \tTraining Loss: 0.120291\n",
      "Epoch: 71 Val Accuracy: 0.844444\n",
      "Epoch: 71 Val Recall: 0.600000\n",
      "Epoch: 71 Test Accuracy: 1.000000\n",
      "Epoch: 71 Test Recall: 0.984444\n",
      "Epoch: 72 \tTraining Loss: 0.136825\n",
      "Epoch: 72 Val Accuracy: 0.855556\n",
      "Epoch: 72 Val Recall: 0.598148\n",
      "Epoch: 72 Test Accuracy: 1.000000\n",
      "Epoch: 72 Test Recall: 0.988889\n",
      "Epoch: 73 \tTraining Loss: 0.077658\n",
      "Epoch: 73 Val Accuracy: 0.866667\n",
      "Epoch: 73 Val Recall: 0.605556\n",
      "Epoch: 73 Test Accuracy: 1.000000\n",
      "Epoch: 73 Test Recall: 0.993333\n",
      "Epoch: 74 \tTraining Loss: 0.131404\n",
      "Epoch: 74 Val Accuracy: 0.888889\n",
      "Epoch: 74 Val Recall: 0.627778\n",
      "Epoch: 74 Test Accuracy: 1.000000\n",
      "Epoch: 74 Test Recall: 0.996111\n",
      "Epoch: 75 \tTraining Loss: 0.079337\n",
      "Epoch: 75 Val Accuracy: 0.877778\n",
      "Epoch: 75 Val Recall: 0.614815\n",
      "Epoch: 75 Test Accuracy: 1.000000\n",
      "Epoch: 75 Test Recall: 0.991667\n",
      "Epoch: 76 \tTraining Loss: 0.125203\n",
      "Epoch: 76 Val Accuracy: 0.777778\n",
      "Epoch: 76 Val Recall: 0.537037\n",
      "Epoch: 76 Test Accuracy: 0.988889\n",
      "Epoch: 76 Test Recall: 0.957778\n",
      "Epoch: 77 \tTraining Loss: 0.125225\n",
      "Epoch: 77 Val Accuracy: 0.855556\n",
      "Epoch: 77 Val Recall: 0.609259\n",
      "Epoch: 77 Test Accuracy: 1.000000\n",
      "Epoch: 77 Test Recall: 0.986667\n",
      "Epoch: 78 \tTraining Loss: 0.139535\n",
      "Epoch: 78 Val Accuracy: 0.855556\n",
      "Epoch: 78 Val Recall: 0.588889\n",
      "Epoch: 78 Test Accuracy: 1.000000\n",
      "Epoch: 78 Test Recall: 0.975556\n",
      "Epoch: 79 \tTraining Loss: 0.108734\n",
      "Epoch: 79 Val Accuracy: 0.877778\n",
      "Epoch: 79 Val Recall: 0.594444\n",
      "Epoch: 79 Test Accuracy: 1.000000\n",
      "Epoch: 79 Test Recall: 0.988333\n",
      "Epoch: 80 \tTraining Loss: 0.085044\n",
      "Epoch: 80 Val Accuracy: 0.833333\n",
      "Epoch: 80 Val Recall: 0.581481\n",
      "Epoch: 80 Test Accuracy: 1.000000\n",
      "Epoch: 80 Test Recall: 0.991111\n",
      "Training time 0:07:12\n",
      "Test Acc: 1.000000 Test Recall: 0.996111\n",
      "Val Acc: 0.911111 Val Recall: 0.633333\n"
     ]
    }
   ],
   "source": [
    "start_time = time.time()\n",
    "val_acc, val_r = 0.0, 0.0\n",
    "test_acc, test_r = 0.0, 0.0\n",
    "for epoch in range(1, epochs + 1):\n",
    "    train(epoch, model)\n",
    "    acc, r = val(epoch, model)\n",
    "    val_acc, val_r = max(acc, val_acc), max(r, val_r)\n",
    "    acc, r = test(epoch, model)\n",
    "    test_acc, test_r = max(acc, test_acc), max(r, test_r)\n",
    "total_time = time.time() - start_time\n",
    "total_time_str = str(datetime.timedelta(seconds=int(total_time)))\n",
    "print(f\"Training time {total_time_str}\")\n",
    "print('Test Acc: {:6f} Test Recall: {:6f}'.format(test_acc, test_r))\n",
    "print('Val Acc: {:6f} Val Recall: {:6f}'.format(val_acc, val_r))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "3459aef6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 1 Test Accuracy: 1.000000\n",
      "Epoch: 1 Test Recall: 0.991111\n",
      "2.138561964035034\n"
     ]
    }
   ],
   "source": [
    "start_time = time.time()\n",
    "test(1, model)\n",
    "total_time = time.time() - start_time\n",
    "print(total_time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "d34c67e4-0058-4e97-8a86-5b3194ab5f98",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "x and y must have same first dimension, but have shapes (50,) and (0,)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[12], line 6\u001b[0m\n\u001b[1;32m      4\u001b[0m plt\u001b[38;5;241m.\u001b[39mtitle(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m不同batch_size大小下损失函数\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m      5\u001b[0m \u001b[38;5;66;03m# plt.plot(list(range(1, 23)), loss_vec4, label='batch_size=4')\u001b[39;00m\n\u001b[0;32m----> 6\u001b[0m \u001b[43mplt\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mplot\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mlist\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mrange\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m51\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvec1\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlabel\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mlr=0.01\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m      7\u001b[0m plt\u001b[38;5;241m.\u001b[39mplot(\u001b[38;5;28mlist\u001b[39m(\u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m51\u001b[39m)), vec2, label\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlr=0.005\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m      8\u001b[0m plt\u001b[38;5;241m.\u001b[39mplot(\u001b[38;5;28mlist\u001b[39m(\u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m51\u001b[39m)), vec3, label\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlr=0.001\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
      "File \u001b[0;32m/data/lambd4/anaconda3/py39/lib/python3.9/site-packages/matplotlib/pyplot.py:3590\u001b[0m, in \u001b[0;36mplot\u001b[0;34m(scalex, scaley, data, *args, **kwargs)\u001b[0m\n\u001b[1;32m   3582\u001b[0m \u001b[38;5;129m@_copy_docstring_and_deprecators\u001b[39m(Axes\u001b[38;5;241m.\u001b[39mplot)\n\u001b[1;32m   3583\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mplot\u001b[39m(\n\u001b[1;32m   3584\u001b[0m     \u001b[38;5;241m*\u001b[39margs: \u001b[38;5;28mfloat\u001b[39m \u001b[38;5;241m|\u001b[39m ArrayLike \u001b[38;5;241m|\u001b[39m \u001b[38;5;28mstr\u001b[39m,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m   3588\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs,\n\u001b[1;32m   3589\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mlist\u001b[39m[Line2D]:\n\u001b[0;32m-> 3590\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mgca\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mplot\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m   3591\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   3592\u001b[0m \u001b[43m        \u001b[49m\u001b[43mscalex\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mscalex\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   3593\u001b[0m \u001b[43m        \u001b[49m\u001b[43mscaley\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mscaley\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   3594\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdata\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m}\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mis\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43m{\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   3595\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   3596\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/data/lambd4/anaconda3/py39/lib/python3.9/site-packages/matplotlib/axes/_axes.py:1724\u001b[0m, in \u001b[0;36mAxes.plot\u001b[0;34m(self, scalex, scaley, data, *args, **kwargs)\u001b[0m\n\u001b[1;32m   1481\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m   1482\u001b[0m \u001b[38;5;124;03mPlot y versus x as lines and/or markers.\u001b[39;00m\n\u001b[1;32m   1483\u001b[0m \n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m   1721\u001b[0m \u001b[38;5;124;03m(``'green'``) or hex strings (``'#008000'``).\u001b[39;00m\n\u001b[1;32m   1722\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m   1723\u001b[0m kwargs \u001b[38;5;241m=\u001b[39m cbook\u001b[38;5;241m.\u001b[39mnormalize_kwargs(kwargs, mlines\u001b[38;5;241m.\u001b[39mLine2D)\n\u001b[0;32m-> 1724\u001b[0m lines \u001b[38;5;241m=\u001b[39m [\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get_lines(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs, data\u001b[38;5;241m=\u001b[39mdata, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)]\n\u001b[1;32m   1725\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m line \u001b[38;5;129;01min\u001b[39;00m lines:\n\u001b[1;32m   1726\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39madd_line(line)\n",
      "File \u001b[0;32m/data/lambd4/anaconda3/py39/lib/python3.9/site-packages/matplotlib/axes/_base.py:303\u001b[0m, in \u001b[0;36m_process_plot_var_args.__call__\u001b[0;34m(self, axes, data, *args, **kwargs)\u001b[0m\n\u001b[1;32m    301\u001b[0m     this \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m0\u001b[39m],\n\u001b[1;32m    302\u001b[0m     args \u001b[38;5;241m=\u001b[39m args[\u001b[38;5;241m1\u001b[39m:]\n\u001b[0;32m--> 303\u001b[0m \u001b[38;5;28;01myield from\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_plot_args\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    304\u001b[0m \u001b[43m    \u001b[49m\u001b[43maxes\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mthis\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mambiguous_fmt_datakey\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mambiguous_fmt_datakey\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/data/lambd4/anaconda3/py39/lib/python3.9/site-packages/matplotlib/axes/_base.py:499\u001b[0m, in \u001b[0;36m_process_plot_var_args._plot_args\u001b[0;34m(self, axes, tup, kwargs, return_kwargs, ambiguous_fmt_datakey)\u001b[0m\n\u001b[1;32m    496\u001b[0m     axes\u001b[38;5;241m.\u001b[39myaxis\u001b[38;5;241m.\u001b[39mupdate_units(y)\n\u001b[1;32m    498\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m x\u001b[38;5;241m.\u001b[39mshape[\u001b[38;5;241m0\u001b[39m] \u001b[38;5;241m!=\u001b[39m y\u001b[38;5;241m.\u001b[39mshape[\u001b[38;5;241m0\u001b[39m]:\n\u001b[0;32m--> 499\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mx and y must have same first dimension, but \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    500\u001b[0m                      \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhave shapes \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mx\u001b[38;5;241m.\u001b[39mshape\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00my\u001b[38;5;241m.\u001b[39mshape\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m    501\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m x\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m2\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m y\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m2\u001b[39m:\n\u001b[1;32m    502\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mx and y can be no greater than 2D, but have \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    503\u001b[0m                      \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mshapes \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mx\u001b[38;5;241m.\u001b[39mshape\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00my\u001b[38;5;241m.\u001b[39mshape\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
      "\u001b[0;31mValueError\u001b[0m: x and y must have same first dimension, but have shapes (50,) and (0,)"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAksAAAHSCAYAAAD8PI8UAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABIgUlEQVR4nO3dd3xUVf7/8fdESIBABggBKSGgSy8SgugalKgUEUTqylJDWcQGkbWAK4KiFBEJTXEFQTqrYglFUClSBBGBZTUgJfQIIZAECJkAc35/8Mt8CZlcSCOT8Ho+HvNHzr3n3s+dS5h37j33jM0YYwQAAAC3vPK7AAAAAE9GWAIAALBAWAIAALBAWAIAALBAWAIAALBAWAIAALBAWAIAALBAWAKAa8TFxWn//v1KTU3N71IKtMuXL6f7+fTp05ozZ45+//33fKoIyD7CEgBcY8SIEapRo4aOHDmSq9udPn26Pv/881zdZk6cP39exYoV0+uvv56uPSkpSXv27LF8HThwwHLb//vf/+Tn56e33nrL1Xbo0CH17dtXq1evzpPjyaqdO3dqz549kqTFixfLZrNp//79kqTvv/9e27Ztc607Z84cBQYG6qeffsqXWpH/iuR3AYA7mzZt0uzZs3NlW+PGjVO5cuU0Y8YMPfPMMzne3uzZsxUeHu76OSwsTOvXr1dMTIyqVauW4+3fCjabTZLkCRP4d+/eXdu2bdOyZctUq1at/C5Hly5dkiT5+Pjk6nZfffVVNWnSRF26dLmp9U+fPq1hw4bl2v5nzpyZoc3hcGS4ArR69Wp17drVcltBQUE6dOhQpsvnzZunixcvqkGDBtmqNc2hQ4dUvXr1HG0jzfU1Dx48WL6+vlq5cmW69ZKSktSjRw+FhIRo+fLlstls2r59u44dO6a77rorV2pBwUNYgkfat2+fZs2alSvbev3111WuXDnXzwMGDJC/v3+WtxMbG6u5c+fmSk3ZsWHDBv3www8KDw8vMKHsRs6fP6/FixfLGKM1a9YU6rCUVefPn8+13wHJfViysnbtWoWFhWVoDwsLswxKV65c0fz582W329WmTZssVpme3W7Xv/71L7fL/vzzT82aNUtdunS5qX83pUuXTvfz8OHD9fjjj2e4WjRu3DhdvnxZs2bNcv1R8euvvyooKEgVKlTI3oGgwCMswSOFh4enu3rjzu+//67g4GCVL19ev//+u0qVKnVT2/7nP/+p2rVrZ7mmX375JV/D0sqVKzV27FiFhYUVmrBUsmRJjRgxQtu3b9eTTz6Z3+VIks6ePSsp44frrVatWrUbXvmrXbu2Ll++7Lp95Al++OEHnThxQpUqVdLzzz/vao+Li5N09ZbX//73P7d927dvr/bt27t+LlOmjN5++22363766aeaNWuW3nnnHdWsWTNLNTocDoWFhalLly5KSEhwjU9zOBySpGnTpqlMmTK6dOmSLl68qG3btumJJ55QSkpKhm3ZbLZ8D9bIe4QlFEiXL19Wnz59lJqaqmnTpt10ULrWL7/8clPrFSlSRI0aNcry9nNb2od4YfPmm2/mdwnpnDp1Sna7Xd7e3vldSp54/fXXtX//ftcVtK+//tp1pWjx4sWu9Y4cOeIa03Ot5ORky+1PnjxZknTixAm3V8a2bt2qrVu3uu1bpUqVdGHJyvr161W6dGnVqFHjpta/VmhoqLZv3y5J6caR1a9fP916//znPxUaGqpLly5p6dKlKl68eIZt1atXL9Pwh8KDsIQCady4cfrll1903333ZfuKxL333ntT6/n7++v06dPZ2kduKqxhydPExcUpICAg2/3XrVun4sWLKyQkREWKWP8Xe/z4ca1YsUIDBgxw3fLJa7GxsTp06JCuXLkiSUpMTHR7W61Pnz6ZbiMoKMht+/fff68VK1aoV69eGa7C/vLLL7r33ns1adIkRURE3HS9O3bs0JIlSxQREaHy5cvr4sWL8vX11bp165SQkCAvr6vPKdntdiUkJEi6+sfUkiVL1LVrV0VHR2vRokUaNGiQ64rslClTlJSUJOnquKjBgwfr0qVL6ty5s/r37+86F9WqVdO4ceMkSS+++KLKli0r6eotwOnTp6tFixY3PQYNBZwBCpjPP//c2Gw2I8m0bt3aGGPMkSNHbtjvww8/NJJMdHS0McaYbdu23dRrx44drvUlmdmzZ6fbbvPmzY0kExMTY1avXm06d+5sAgICzN133226d+9uDhw44LaeP//804wYMcIEBwebUqVKmYCAANOqVSvz888/p1tv5MiRRpLb1/W1pKSkmHfeecc89NBDxm63m5o1a5revXubffv2pVsvrb8xxnz33XcmLCzMlCxZ0lStWtUMHDjQnD9//obv542cOnXKvPjii6Z27dqmRIkSJjg42AwePNj8+eef6darUKGC6/27mWOWZEaOHJlhf4sXLzatW7c2ZcuWNXfddZd56qmnMhx3dHS05Xaz8mrevHmGGpxOp6levbrx9fU1KSkp6Zb5+vpm6PPyyy8bSeabb77J0nubplatWqZq1apm9+7dWe577tw5I8m8+uqr2dr39RISEszdd99t7HZ7hnNsjDGbN282ksyUKVOytN158+YZSWb37t3m+eefN40aNTIxMTHmscceM5MnTzbR0dGmX79+pmLFiq4+//rXv4wks2LFCrNo0SIjyWzYsCHDto8cOWKqV69ufHx8jCTj7+9vHn74YfPHH38YY4w5ffq0KVasmJFkli1b5ur32WefGUnmyy+/zNKxoODiyhIKlPXr16tHjx7y9fXV+fPnJUljxozRyJEj9c477+ill15y/aV5I02aNMnV2gYPHqyoqChVr15dTZs21c6dO7Vw4UKtXLlSK1eu1H333edad8mSJerXr5+Sk5NVrVo116DZ1atXa+3atVq3bp0eeOABSVLDhg3Vo0cPffvtt4qPj1eLFi1cA02vfTpn//796tChg3777TeVLl1aTZs2VVJSkhYsWKBvv/1WBw4cUMmSJdPV/MYbb+jtt99WrVq19OCDD2rDhg3697//rVOnTunLL7/M9ntx/vx5Pfzww/rtt99Uo0YNtWrVSvv27dOUKVO0dOlS/fHHH25vaaRJO+ZrJScn68svv5TNZlOLFi1c7VeuXFHfvn01b948lS1bVvfdd5/OnTunL774QitWrNCKFSvUrFkzSZK3t7flYOCUlBQdPnxYkuTn56eKFStmum7VqlUztO3fv18xMTHq0KHDTY1jefnll/XBBx/otdde0+OPP6477rjjhn2ud+TIETVs2FC9evXS6NGj3daVFfv27XNddbJSunRp3Xnnna6fp0+frgMHDuiDDz5wOxA67cqon59ftmsbPny4mjdvrjZt2mjz5s0qU6aMJKlYsWKuf9vfffedxowZo7Fjx6pNmzbpbi1ea926derbt69Kliypd999V0OGDNHKlSs1cuRINWjQwHV7OG2c0rZt29S2bVtJVwd8S1LTpk2zfSwoYPI7rQE3a/PmzcZut5tSpUqZzZs3mzvuuMO0bt3aHD582Nx///1Gknn00UfN8ePH3fa//sqSMcb85z//MfPmzcv09e2337rWvdGVpYoVK6Zb/8qVK+b55583kkxoaKhxOp2uZYcPHzY9e/Y0e/bscbU5nU7z+uuvp7tidq377rvPSDJr167NsOzKlSsmNDTUSDI9e/ZMd2Vo+/btZuXKlenW1/+/OlK+fHmzceNGV/t///tf4+XlZWw2W7orPVm1YMECI8n87W9/M1euXHG1b9myxSxfvjzduu6uLLnz4osvGklmyJAh6dqnTp1qJJmOHTuahIQEV/uvv/5qSpUqZZo0aZLuvbcye/Zs13tTq1atm+6XZtq0aUaS+fjjjzMsc3dlyRhjXn31VSPJfPrpp1nalzFXryyVL1/edOzY0UgyPj4+5pVXXjFnz569Yd/MriylnY8bvZ5++ul0/ZxOp1m1apW5fPmy2/2lXSHK6tWYa68sGXP1d8ff39+0atXKdX569eplgoODzYkTJ0z58uVNnz59XMuuv7LkdDrNwIEDjSTTtGlTc/LkSdc6+/btM5cvXzYjRowwzz33nLHb7aZOnTqmbt265vHHH3fV1Lp1a1OlSpUsHQcKNsISCoT58+cbHx8f4+fnZ7Zs2WKMMa6wZIwxqampZujQoa5L6StWrMiwDXdhyd/f3/IDITQ01LXujcLStm3bMuwzJSXFBAQEGEnml19+ueFxJiUlGZvNZooVK5bhg9oqLH366adGkqlbt665dOnSDfeTdnxptxuulRa63L2HNystNIwbN+6G695MWNq4caOx2WzmL3/5i7lw4YKrPTEx0ZQqVcpUqlTJnDt3LkO/4cOHG0lm69atN1V3Wuj4+9//nul7beWJJ54wktwG9szCUlxcnClZsqQJCgrKcOvuRmrVqmXuvvtuY4wxq1atMrVq1TKSzJ133mm++uory77XhqXU1FSzZs0ac+XKFVOhQgXTp08fy7533HFHhrD0yiuvmP79+2f6euCBB1x/CFit179//3Tn6/qwZIwx3377rZkzZ47r544dO5oHH3zQnDp1yowcOTLd++juNty7775rRowYYVJTU82VK1fM0KFDTenSpdP9G3z66aeNJLN8+XITERFhSpcubVJTU43D4TClS5c2nTt3tnyPULgQluDRLl265Bp/YLfb0/0nem1YSvP1118bu91uvLy8zIcffphuWWZh6bnnnnO77+bNm2cpLGU2bqRHjx5Gkpk3b16mx3n69Gmzfv16M336dNf4ievHfViFpX/84x9GkpkxY0am+7hWWli6ePFihmVPPfWUkWRmzpx5U9ty58CBA6ZkyZKmdOnS5pNPPnG7nzQ3CkvJycmmZs2axmazmR9//DHdsg0bNhhJZtCgQW77fvHFFzd876/dT4kSJUyzZs1MTEyM8fLyMn/7299u2C/NmTNnTIkSJUzjxo3dLs8sLBljzGuvvZal85fm2rBkjDEOh8OMHz/eeHt7G0mme/fu5vTp0277/vnnn0aSqV69uilTpoyRZA4dOpQhLK1fv96MHj06XUh1F5aCgoJybTzYokWLXNt1F5aMuXqF6PDhw8YYY1q2bGnatGljfvnllwyh2WrMkjHGREVFGUlm4cKF6dqPHj1qXnjhBeN0Os0333xjJJmVK1ear7/+2kgyU6dOdbs9FE583Qk81tatW3XvvffqnXfe0V133aV169bdcIxA+/bttWHDBlWoUEHPPPOMhg0bJqfTeYsqdq9SpUqSlOGJo9OnT+v9999X/fr1Va5cOT366KP64IMPXPVevHjxpvexa9cuSVcfY86pYsWKSfq/yRmz46677tJ3332n+vXrq1+/fqpSpYpeeuklxcTEZHlbb7zxhv744w8NGTJEDz74YLplu3fvliTNmDFDNpstw6tz586SpKNHj95wPx999JGSk5P11FNPqVq1anriiSe0dOlSt4/PuzNjxgwlJyfrH//4RxaPUHruuedks9lyPI+Xt7e3XnnlFW3btk1169bVwoUL033lyJUrVzRlyhS1atVKgYGBkq7OWP3UU0/pu+++U+XKlTNsc82aNRoxYsQNpww4dOiQzNU/wDO8Tp8+rRIlSrjGFc2aNSvTdY0x6tatm+W+/vjjD7Vu3dq13vnz51W0aFF16NBBISEh2rlzp2X/pUuXavHixVq8eLHGjBkjb29vXb582dW2ePFibdy4UT169JDNZlPz5s1VrFgxffbZZ1q4cKGKFy+eYUwdCjcGeMMjvfbaaxo3bpyMMerSpYtmzpwpu91+U30bNGigTZs2qVWrVho/frzKli2rV155JY8rzlzaI8rXTnK4Z88etWzZUmfPntWAAQM0e/Zs3XPPPfL29tadd96pkydPZmkfaQNyb3Zw+61w//3368cff9SPP/6o8ePHa+LEiZo6daomTJigwYMH39Q2tmzZovfff19/+ctf9M4772RYnhYsa9WqZTlgv3Hjxpb7SUhI0OjRo1W2bFl1795dkjR06FB9/fXXGjhwoNatW2f53p47d05TpkxRuXLl1Lt375s5tHQqVaqkZs2aacOGDYqJicnxV3w0bNhQv/zyi9577z0NHTrU1e7l5aUxY8aoaNGi6tu3r/79739rwIABrsfj3Ul7j3MytcG0adOUnJysjz/+WB999JFGjBihbt26qUSJElnazsWLFzV27FiNHz9etWvX1rx58yRJZ86cUe3atfXdd9+pY8eOuv/++/Xxxx+rV69ebrczcOBAxcfHp2tzd9769Omj++67T35+furYsaOWLl0qh8Ohbt26uQaX4/ZAWIJHuu+++xQYGKjJkyfrySefzPJ/1NWrV9fGjRv19ttvp5tF2J0LFy7ozz//zNCempqaK+Hjjz/+kCTVqVPH1dazZ0/FxsZq69atCgkJyfE+6tatq+3bt2vPnj2up+g8Qdpf5c2bN9fu3bvVvn17DRkyRKGhoTc87pSUFPXt21fGGM2ePdvtB2vaJIJ16tTR/Pnzs13nO++8ozNnzmjatGmuuXQeeugh9e7dW3PnztXHH3+sp59+OtP+L7/8sv7880+99957WQ4Aaf72t79pw4YNWrRokV577bVsbeNaxYsX14gRI9K12Ww2bd68WdWrV9eFCxf073//+4bbOXnypIoWLZrtcPDf//5X7733nu6880716tVL1atXV4sWLTR69GiNHTv2prfzv//9T+3bt9fhw4f16quvatSoUfL29tbFixe1f/9+denSRbVr19bPP/+sbt26qXfv3jp58qSqVKmSYVunT5+WMUaPPvqo9u3bp3379qlYsWJKSUlRhQoV9Pe//10zZsxI1yc8PFyLFi2SpFz5jkkULJ7zZyhwjSeffNL1KHx2/6KtUKGCpk6desMPrzlz5qhixYoZXrnxDeN79uzR+vXrVbx4cdcs4ImJifr1119Vv379DIHBGJPpY9tpx+Hu9lzaBJsffvhhvt92zEyDBg303HPPSbr6PXc3MmrUKO3Zs0cRERGuR/+v17BhQxUvXlxr165VbGxstupasWKFJk6cqHr16mUIRBMnTlS5cuX00ksvacuWLW77nz17VqtWrVKTJk00ZMiQbNUgSZ07d5bNZtOCBQuyvY2bcdddd93079Tly5e1Zs0a1a5dO1t/OJw8eVJPPPGEkpOTNXv2bPn4+OjRRx9Vly5dNG7cOE2d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7bffqmvXrhnW6dy5s+vpx6woU6aM/vOf/6Q7V06nU+fOndOIESPUvn171a5d27Vs7ty5eu6557Rx40bt2bNH7733XoZpS4KCgrR582Y9++yz6tSpU46mVUDBYDPGmPwu4lp79uxxTQq2d+9erV27VmFhYTfs53A4NGzYMC1fvlyJiYl66KGHFBkZ6XaSNQA3Lzw8XJ9++ulNrRsUFJRh8k0UTk6nU1euXMk0VBV0xhhCEFw8Liw9/PDD2rZtm1JTU3Xp0qWbCkvGGD322GNas2aNBg8erHLlymnatGkqWrSotmzZku6bsQEAALLC4+ZZWrt2rc6fP68xY8bcdJ9169Zp9erVmjRpkiZOnKjhw4drxYoVOnLkSIaJxQAAALLC48JSdsycOVM+Pj4KDw93td1zzz164IEHNGvWrPwrDAAAFHiFIixFR0erUaNGri9pTBMaGqpjx47p/Pnz+VQZAAAo6ArF03CxsbFuv0QzICBAknTixAnVrFnTbV+HwyGHw+H62el06syZM/L392dwHwAABYQxRufOnVOlSpVy/UvFC0VYio+Pl5+fX4b2tLbTp09nGpbGjh2rN998M0/rAwAAt8bRo0fdfoFyThSKsFSuXDklJiZmaE9rS7vC5M7w4cM1dOjQdH2qVq2qo0ePug1gAADA8yQlJSkwMFClSpXK9W0XirBUqVIlnTp1KkN7XFyca3lmfHx85OPjk6Hdz8+PsAQAQAGTF0NoCsUA73r16mnXrl1KSkpK175hwwZVq1ZNvr6++VQZAAAo6ApcWNq9e7dat26tdevWudoGDBig1NRUzZ4929W2Y8cObdmyRf3798+HKgEAQGHhUbfhDhw4oJ9++kmStH37dknSd999p2PHjsnX11cdO3bUvHnztHr1atntdtfM3s2aNVO7du300ksv6ciRI64ZvKtXr66BAwfm1+EAAIBCwKPC0oYNG9S3b990bWkzeQcFBaljx45q06aNFi1apA4dOrjWsdls+uKLLzRs2DBFRUUpISFBzZs3V2RkpMqXL38rDwEAABQyHvfdcPktKSlJdrtdiYmJDPAGAKCAyMvP7wI3ZgkAAOBWIiwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABYICwBAABY8MiwlJCQoL59+yooKEiBgYHq16+fEhMTb9jv8OHD6tmzpypVqqTSpUsrLCxMGzZsuAUVAwCAwqpIfhdwveTkZIWFhengwYMaMmSIvLy8FBkZqR07dmjz5s0qXry4236JiYl6+OGHlZCQoIiICPn5+emTTz7RI488op9//lnBwcG3+EgAAEBh4HFhacmSJdq1a5eioqLUrl07SVKTJk3Uvn17LVmyROHh4W77LVu2TDExMVq1apVatWolSerXr5/+8pe/6KOPPtKMGTNu1SEAAIBCxONuw82cOVNVqlRR27ZtXW1t27ZV5cqVNWvWrEz7xcbGSpL++te/utr8/PzUrFkzHTt2LO8KBgAAhZrHhaXo6GiFhobKZrO52ry8vBQaGqro6OhM+7Vo0UKStGbNmnTt+/fvV7NmzfKmWAAAUOh51G24lJQUnT17VgEBARmWBQQEKD4+Xg6HQz4+PhmWN2rUSLNmzVL//v116tQphYeHa9WqVSpZsqReeOGFTPfpcDjkcDhcPyclJeXOwQAAgELBo64snTlzRtLV22fXS2uLj4/PtH/VqlXl7e2tiRMnqnbt2urevbveeust+fr6Ztpn7NixstvtrldgYGAOjwIAABQmHhWW/P39JcntNAFpbWnrXG/ZsmXq0KGDZs6cqd9//11TpkxRvXr19MQTT+iLL77IdJ/Dhw9XYmKi63X06NFcOBIAAFBYeFRY8vHxkb+/v06dOpVhWVxcnAICAtzegjPGaPDgwQoPD9fjjz8uLy8vtW3bVuvXr1dISIgGDBigCxcuZLpPPz+/dC8AAIA0HhWWJKlevXratGmTnE6nq83p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kNaWto4VY4yGDh2qCxcuaOzYsZbrDh8+XImJia7X0aNHs1E5AAAorDzqNpyPj4/8/f116tSpDMvi4uIUEBBwU7fgxo0bp/nz5+vDDz9UgwYNbrjPm72tBwAAbj8edWVJkurVq6dNmzbJ6XS62pxOpzZu3Kh69erdsP+8efP02muvadCgQRo0aFBelgoAAG4DHheWBgwYoBMnTigqKsrVFhUVpdjYWPXv31+StHv3brVu3Vrr1q1L1/eDDz5Qnz591LdvX02bNu1Wlg0AAAopj7oNJ0ldu3bV5MmT1atXL0VERMjLy0uTJk1SSEiIunTpIunq1aPVq1fLbrcrLCxMxhi99dZbGjVqlBo3bqwnn3xSS5YsSXd1qmXLlqpQoUJ+HRYAACigPG5SSunq4/sRERH6/vvvZYxRixYtFBkZKbvdLklau3atevfurfHjx6t79+46dOiQqlevbrnNtWvXKiws7Kb2zaSUAAAULHn5+e2RYSk/EZYAACh4bqsZvAEAADwJYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMACYQkAAMCCR4alhIQE9e3bV0FBQQoMDFS/fv2UmJh4w34Oh0MvvviiatasqQoVKqhr1646fvz4LagYAAAUVkXyu4DrJScnKywsTAcPHtSQIUPk5eWlyMhI7dixQ5s3b1bx4sXd9jPGqH379lqzZo0GDx6scuXKadq0aQoNDdWWLVt055133uIjAQAAhYHHhaUlS5Zo165dioqKUrt27SRJTZo0Ufv27bVkyRKFh4e77bdu3TqtXr1aU6dO1fPPPy9JevzxxxUcHKwZM2Zo1KhRt+gIAABAYWIzxpj8LuJaoaGhOnLkiI4cOSKbzSZJcjqdqlq1qqpXr64NGza47dejRw998cUXOn36tEqWLOlqb9asmQ4fPqyjR4/e1P6TkpJkt9uVmJgoPz+/nB8QAADIc3n5+e1xY5aio6MVGhrqCkqS5OXlpdDQUEVHR1v2a9SoUbqgJF0NX8eOHdP58+fzrGYAAFB4edRtuJSUFJ09e1YBAQEZlgUEBCg+Pl4Oh0M+Pj4ZlsfGxqpJkyZu+0nSiRMnVLNmzQzLHQ6HHA6H6+e0geRJSUnZPg4AAHBrpX1u58UNM48KS2fOnJEkt5fP0tri4+NVqVKlDMvj4+Mt+50+fdptWBo7dqzefPPNDO2BgYFZKx4AAOS7+Ph42e32XN2mR4Ulf39/SXI7TUBaW9o61ytXrpxlP3dXqyRp+PDhGjp0qOvnhIQEBQUF6ciRI7n+ZiNrkpKSFBgYqKNHjzJ+LJ9xLjwH58JzcC48S2JioqpWraqyZcvm+rY9Kiz5+PjI399fp06dyrAsLi5OAQEBbm/BSVKlSpUy7Ze2PLN9utum3W7nH7+H8PPz41x4CM6F5+BceA7OhWfx8sr94dgeN8C7Xr162rRpk5xOp6vN6XRq48aNqlevnmW/Xbt2ZRhrtGHDBlWrVk2+vr55VjMAACi8PC4sDRgwQCdOnFBUVJSrLSoqSrGxserfv78kaffu3WrdurXWrVuXrl9qaqpmz57tatuxY4e2bNni6gcAAJBVHnUbTpK6du2qyZMnq1evXoqIiJCXl5cmTZqkkJAQdenSRZI0b948rV69Wna7XWFhYZKuzqfUrl07vfTSSzpy5IhrBu/q1atr4MCBN71/Hx8fjRw5MtPbfbh1OBeeg3PhOTgXnoNz4Vny8nx43KSU0tVBcxEREfr+++9ljFGLFi0UGRnpGnC9du1a9e7dW+PHj1f37t1d/VJTUzVs2DAtW7ZMCQkJat68uSIjI1W5cuX8OhQAAFDAeWRYAgAA8BQeN2YJAADAkxCWAAAALBCWAAAALNxWYSkhIUF9+/ZVUFCQAgMD1a9fP7ezfl/P4XDoxRdfVM2aNVWhQgV17dpVx48fvwUVF17ZORfGGM2YMUMNGjRQ8eLFVaNGDUVERPA9fjmU3d+Lay1cuFA2m831dCqyJyfnIjo6Wh07dlSVKlVUsWJFderUSb/99lseV1y4Zfd8HD58WD179lSlSpVUunRphYWFacOGDbeg4sJrz549GjVqlGrXri2bzZZu6iArufX5fdsM8E5OTtYDDzyggwcPasiQIfLy8lJkZKTuuusubd68WcWLF3fbzxijxx57TGvWrNHgwYNdUxIULVpUW7Zs0Z133nmLj6Tgy865cDgcGjBggD7//HN17dpV9913n3bu3KlZs2YpNDRU69evz5NZWwu77P5eXCs2Nlb16tVTUlKSmjVrdtP/iSG9nJyLb7/9Vp07d1blypXVs2dPlSpVSkuXLlVcXJx2796tokWL3sIjKRyyez4SExMVHByshIQERUREyM/PT5988omio6P1888/Kzg4+BYfSeHw8MMPa9u2bUpNTdWlS5e0du3aG/5xlquf3+Y28cknnxhJJioqytX2zTffGElm9uzZmfZbs2aNkWSmTp3qatu5c6ex2Wxm5MiReVhx4ZWdc3H58mXz8ssvm59++ild+1tvvWUkme+++y4vSy60svt7kcbpdJonnnjCNGzY0DRr1sw0b94874ot5LJ7LlJTU83dd99tGjdubBISElztV65cMX/++WdellyoZfd8zJ8/30gyq1atcrUlJiaagIAA8/TTT+dlybeFCRMmGElm7dq1N1w3Nz+/b5uw9MADD5gqVaoYp9Pparty5YqpXLmyadasWab9unfvbnx8fMy5c+fStYeGhpoqVarkWb2FWXbPhTs7duwwkszEiRNzu8zbQk7PxaeffmokmR9++ME0b96csJQD2T0Xc+bMMZLMN998cyvKvG1k93ykfZgnJSWla+/YsaNp27ZtntV7u8hKWMrNz+/b5r5FdHS0QkNDZbPZXG1eXl4KDQ1VdHS0Zb9GjRqpZMmS6dpDQ0N17NgxnT9/Ps9qLqyyey7ciY+PlySVL18+V2u8XeTkXBw/flyDBw/WM888o0ceeSSvSy30snsufv75Z3l7e6tt27aSrt6yNrfH6Io8ld3z0aJFC0nSmjVr0rXv379fzZo1y5ti4VZufn7fFmEpJSVFZ8+eVUBAQIZlAQEBio+Pl8PhcNs3NjY2036SdOLEidwttpDLyblw58cff5QkNWnSJNdqvF3k5FwYYzRw4ECVL19eEyZMyOtSC72cnIuYmBhVrlxZ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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# show train pic\n",
    "plt.ylabel(\"loss\")\n",
    "plt.xlabel(\"step\")\n",
    "plt.title(\"不同batch_size大小下损失函数\")\n",
    "# plt.plot(list(range(1, 23)), loss_vec4, label='batch_size=4')\n",
    "plt.plot(list(range(1, 51)), vec1, label='lr=0.01')\n",
    "plt.plot(list(range(1, 51)), vec2, label='lr=0.005')\n",
    "plt.plot(list(range(1, 51)), vec3, label='lr=0.001')\n",
    "plt.plot(list(range(1, 51)), vec4, label='lr=0.0005')\n",
    "plt.legend()\n",
    "plt.show()\n",
    "# matrix = np.mat([loss_vec4, loss_vec8, loss_vec16, loss_vec32])\n",
    "# scio.savemat('batch_size.mat', {'data': matrix})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b082135",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 训练结果图\n",
    "plt.ylabel(\"loss\")\n",
    "plt.xlabel(\"step\")\n",
    "plt.plot(list(range(1, 81)), loss_vec32)\n",
    "plt.show()\n",
    "\n",
    "plt.ylabel(\"Acc\")\n",
    "plt.xlabel(\"step\")\n",
    "plt.plot(list(range(1, 81)), acc_vec)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "753f0644-def1-4c54-b8df-8fd6234d3ead",
   "metadata": {},
   "outputs": [],
   "source": [
    "s = time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime())\n",
    "torch.save(best_model_wts, f'save_model/float/ecgid_model_{s}.pt')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
